Skip to content

Method: static {...}

1: /*
2: * *********************************************************************************************************************
3: *
4: * TheseFoolishThings: Miscellaneous utilities
5: * http://tidalwave.it/projects/thesefoolishthings
6: *
7: * Copyright (C) 2009 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
23: * git clone https://github.com/tidalwave-it/thesefoolishthings-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.util;
28:
29: import javax.annotation.Nonnegative;
30: import javax.annotation.Nonnull;
31: import java.util.Collection;
32: import java.util.Collections;
33: import java.util.Comparator;
34: import java.util.Iterator;
35: import java.util.List;
36: import java.util.Optional;
37: import java.util.stream.Stream;
38: import java.io.Serializable;
39: import it.tidalwave.util.impl.ArrayListFinder;
40: import lombok.AccessLevel;
41: import lombok.AllArgsConstructor;
42: import lombok.EqualsAndHashCode;
43: import lombok.RequiredArgsConstructor;
44: import lombok.ToString;
45:
46: /***********************************************************************************************************************
47: *
48: * A factory for providing results of a search. {@code Finder} implementations must be <em>immutable</em>.
49: *
50: * @author Fabrizio Giudici
51: * @it.tidalwave.javadoc.draft
52: *
53: **********************************************************************************************************************/
54: public interface Finder<TYPE> extends Cloneable, Serializable
55: {
56: /*******************************************************************************************************************
57: *
58: * A tag interface to mark objects which are meaningful sort criteria that can be passed to
59: * {@link Finder#sort(it.tidalwave.util.Finder.SortCriterion)}. In general, a {@code SortCriterion} is just a
60: * behaviourless and methodless object, that should be specifically handled by concrete implementations of
61: * {@link Finder}. The only exceptions are {@link InMemorySortCriterion} objects.
62: *
63: ******************************************************************************************************************/
64: public static interface SortCriterion
65: {
66: public static final Class<SortCriterion> _SortCriterion_ = SortCriterion.class;
67:
68: /** A special {@link SortCriterion} which indicates that no sort has been performed. */
69: public static final SortCriterion UNSORTED = (InMemorySortCriterion<Object>)(results, sortDirection) -> {};
70:
71: public static final SortCriterion DEFAULT = UNSORTED;
72: }
73:
74: /*******************************************************************************************************************
75: *
76: * An interface that should be implemented by specific {@link SortCriterion} objects which are capable to implement
77: * by themselves the sorting of objects, by post-processing an existing collection of objects. While this is often
78: * convenient, it is possible for it to be inefficient in cases in which the original source of objects is capable
79: * to perform the sort in an optimized way (e.g. an SQL database by means of {@code ORDER BY}). The facility class
80: * {@link it.tidalwave.util.spi.HierarchicFinderSupport} supports {@code FilterSortCriterion} objects out of the box.
81: *
82: ******************************************************************************************************************/
83: public static interface InMemorySortCriterion<TYPE> extends SortCriterion
84: {
85: /***************************************************************************************************************
86: *
87: * Performs the sort of results.
88: *
89: * @param results the list of objects to be sorted in place
90: *
91: **************************************************************************************************************/
92: public default void sort (@Nonnull final List<? extends TYPE> results)
93: {
94: sort(results, SortDirection.ASCENDING);
95: }
96:
97: /***************************************************************************************************************
98: *
99: * Performs the sort of results.
100: *
101: * @param results the list of objects to be sorted in place
102: * @param sortDirection the sort direction
103: *
104: **************************************************************************************************************/
105: // START SNIPPET: sort
106: public void sort (@Nonnull List<? extends TYPE> results, @Nonnull SortDirection sortDirection);
107: // END SNIPPET: sort
108:
109: /***************************************************************************************************************
110: *
111: * Creates a new in-memory {@code SortCriterion} based on a {@link Comparator}.
112: *
113: * @param <T> the type of the objects to compare
114: * @param comparator the {@code Comparator}
115: * @return the new {@code SortCriterion}
116: *
117: **************************************************************************************************************/
118: @Nonnull
119: public static <T> InMemorySortCriterion<T> of (@Nonnull final Comparator<? super T> comparator)
120: {
121: return of(comparator, comparator.getClass().getSimpleName());
122: }
123:
124: /***************************************************************************************************************
125: *
126: * Creates a new in-memory {@code SortCriterion} based on a {@link Comparator}.
127: *
128: * @param <T> the type of the objects to compare
129: * @param comparator the {@code Comparator}
130: * @param name a name
131: * @return the new {@code SortCriterion}
132: *
133: **************************************************************************************************************/
134: @Nonnull
135: public static <T> InMemorySortCriterion<T> of (@Nonnull final Comparator<? super T> comparator,
136: @Nonnull final String name)
137: {
138: return new DefaultInMemorySortCriterion<>(comparator, name);
139: }
140:
141: /***************************************************************************************************************
142: *
143: **************************************************************************************************************/
144: @AllArgsConstructor @ToString @EqualsAndHashCode
145: static class DefaultInMemorySortCriterion<T> implements Finder.InMemorySortCriterion<T>, Serializable
146: {
147: private static final long serialVersionUID = 76093596048395982L;
148:
149: @Nonnull
150: private final Comparator<? super T> comparator;
151:
152: @Nonnull
153: private final String name;
154:
155: @Override
156: public void sort (@Nonnull final List<? extends T> results, @Nonnull final SortDirection sortDirection)
157: {
158: results.sort((Comparator<T>)(o1, o2) -> comparator.compare(o1, o2) * sortDirection.intValue());
159: }
160: }
161: }
162:
163: /*******************************************************************************************************************
164: *
165: * An enumeration to define the direction of a sort (ascending or descending).
166: *
167: * @it.tidalwave.javadoc.stable
168: *
169: ******************************************************************************************************************/
170: @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
171: public static enum SortDirection
172: {
173: ASCENDING(+1), DESCENDING(-1);
174:
175: private final int intValue;
176:
177: /** @return +1 for ascending direction, -1 for descending */
178: public int intValue()
179: {
180: return intValue;
181: }
182: }
183:
184: /*******************************************************************************************************************
185: *
186: * Tells the {@code Finder} that only a subset of found items will be returned, starting from the given position.
187: *
188: * @param firstResult the index of the first result to return
189: * @return the {@code Finder}
190: *
191: ******************************************************************************************************************/
192: // START SNIPPET: from
193: @Nonnull
194: public Finder<TYPE> from (@Nonnegative int firstResult);
195: // END SNIPPET: from
196:
197: /*******************************************************************************************************************
198: *
199: * Tells the {@code Finder} that only a maximum number of found items will be returned.
200: *
201: * @param maxResults the max number of results to return
202: * @return the {@code Finder}
203: *
204: ******************************************************************************************************************/
205: // START SNIPPET: max
206: @Nonnull
207: public Finder<TYPE> max (@Nonnegative int maxResults);
208: // END SNIPPET: max
209:
210: /*******************************************************************************************************************
211: *
212: * Tells the {@code Finder} that results should be created with the given context. This method can be called
213: * multiple times; contexts are accumulated.
214: *
215: * @param context the context
216: * @return the {@code Finder}
217: *
218: ******************************************************************************************************************/
219: @Nonnull
220: public default Finder<TYPE> withContext (@Nonnull final Object context)
221: {
222: throw new UnsupportedOperationException("Not implemented yet.");
223: }
224:
225: /*******************************************************************************************************************
226: *
227: * Tells the {@code Finder} that the specified type of results is expected.
228: *
229: * @param <ANOTHER_TYPE> the static type
230: * @param type the dynamic type
231: * @return the {@code Finder}
232: *
233: ******************************************************************************************************************/
234: @Nonnull
235: public default <ANOTHER_TYPE> Finder<ANOTHER_TYPE> ofType (@Nonnull final Class<ANOTHER_TYPE> type)
236: {
237: throw new UnsupportedOperationException("Not implemented yet.");
238: }
239:
240: /*******************************************************************************************************************
241: *
242: * Tells the {@code Finder} that results will be sorted according to the given criterion, in ascending direction.
243: *
244: * @param criterion the sort criterion
245: * @return the {@code Finder}
246: *
247: ******************************************************************************************************************/
248: @Nonnull
249: public default Finder<TYPE> sort (@Nonnull final SortCriterion criterion)
250: {
251: return sort(criterion, SortDirection.ASCENDING);
252: }
253:
254:
255: /*******************************************************************************************************************
256: *
257: * Tells the {@code Finder} that results will be sorted according to the given criterion and direction.
258: *
259: * @param criterion the sort criterion
260: * @param direction the sort direction
261: * @return the {@code Finder}
262: *
263: ******************************************************************************************************************/
264: @Nonnull
265: public Finder<TYPE> sort (@Nonnull SortCriterion criterion, @Nonnull SortDirection direction);
266:
267: /*******************************************************************************************************************
268: *
269: * Performs the search and returns the found items.
270: *
271: * @return the searched items
272: *
273: ******************************************************************************************************************/
274: // START SNIPPET: results
275: @Nonnull
276: public List<? extends TYPE> results();
277: // END SNIPPET: results
278:
279: /*******************************************************************************************************************
280: *
281: * Performs the search and returns the count of found items.
282: *
283: * @return the count of found items
284: *
285: ******************************************************************************************************************/
286: // START SNIPPET: count
287: @Nonnegative
288: public int count();
289: // END SNIPPET: count
290:
291: /*******************************************************************************************************************
292: *
293: * Performs the search assuming that it will return a single item and returns it. This method fails if the search
294: * returns more than one single item.
295: *
296: * @return the optional result
297: * @throws RuntimeException if the search returned more than one single item
298: *
299: * @since 3.2-ALPHA-1 (previously in Finder8)
300: *
301: ******************************************************************************************************************/
302: // START SNIPPET: optionalResult
303: @Nonnull
304: public default Optional<TYPE> optionalResult()
305: // END SNIPPET: optionalResult
306: {
307: final List<TYPE> results = (List<TYPE>)results();
308:
309: if (results.size() > 1)
310: {
311: throw new RuntimeException("" + results.size() + " results, expected only one");
312: }
313:
314: return results.stream().findFirst();
315: }
316:
317: /*******************************************************************************************************************
318: *
319: * Performs the search and returns only the first found item.
320: *
321: * @return the first result
322: * @since 3.2-ALPHA-1 (previously in Finder8)
323: *
324: ******************************************************************************************************************/
325: // START SNIPPET: optionalFirstResult
326: @Nonnull
327: public default Optional<TYPE> optionalFirstResult()
328: // END SNIPPET: optionalFirstResult
329: {
330: return stream().findFirst();
331: }
332:
333: /*******************************************************************************************************************
334: *
335: * Returns a stream of results.
336: *
337: * @return the stream
338: * @since 3.2-ALPHA-1 (previously in Finder8)
339: *
340: ******************************************************************************************************************/
341: @Nonnull
342: public default Stream<TYPE> stream()
343: {
344: return ((List<TYPE>)results()).stream();
345: }
346:
347: /*******************************************************************************************************************
348: *
349: * Returns am iterator of results.
350: *
351: * @return the iterator
352: * @since 3.2-ALPHA-1 (previously in Finder8)
353: *
354: ******************************************************************************************************************/
355: @Nonnull
356: public default Iterator<TYPE> iterator()
357: {
358: return ((List<TYPE>)results()).iterator();
359: }
360:
361: /*******************************************************************************************************************
362: *
363: * Performs the search assuming that it will return a single item and returns it. This method fails if the search
364: * returns more than one single item.
365: *
366: * @return the found item
367: * @throws NotFoundException if the search didn't find anything
368: * @throws RuntimeException if the search returned more than one single item
369: * @deprecated Use {@link #optionalResult()} instead
370: *
371: ******************************************************************************************************************/
372: @Nonnull @Deprecated
373: public default TYPE result()
374: throws NotFoundException, RuntimeException
375: {
376: return optionalResult().orElseThrow(NotFoundException::new);
377: }
378:
379: /*******************************************************************************************************************
380: *
381: * Performs the search and returns only the first found item.
382: *
383: * @return the first found item
384: * @throws NotFoundException if the search didn't find anything
385: * @deprecated Use {@link #optionalFirstResult()} instead
386: *
387: ******************************************************************************************************************/
388: @Nonnull @Deprecated
389: public default TYPE firstResult()
390: throws NotFoundException
391: {
392: return optionalFirstResult().orElseThrow(NotFoundException::new);
393: }
394:
395: /*******************************************************************************************************************
396: *
397: * Returns an empty {@code Finder}.
398: *
399: * @param <T> the type of the {@code Finder}
400: * @return the empty {@code Finder}
401: * @since 3.2-ALPHA-1 (previously in HierarchicFinderSupport.emptyFinder())
402: *
403: ******************************************************************************************************************/
404: @Nonnull
405: public static <T> Finder<T> empty()
406: {
407: return ofCloned(Collections.emptyList());
408: }
409:
410: /*******************************************************************************************************************
411: *
412: * Returns a wrapped {@code Finder} on a given collection of elements. The collection is cloned and will be
413: * immutable
414: *
415: * @param <T> the type of the {@code Finder}
416: * @param items the objects to wrap
417: * @return the wrapped {@code Finder}
418: * @since 3.2-ALPHA-1
419: *
420: ******************************************************************************************************************/
421: @Nonnull
422: public static <T> Finder<T> ofCloned (@Nonnull final Collection<T> items)
423: {
424: return new ArrayListFinder<>(items);
425: }
426: }